<!-- 权限管理-用户管理 -->
<template>
    <!-- 子组件：顶部搜索 -->
    <Searchbox @searchEvent="searchUser" @resetEvent="resetUserList" />
    <!-- 显示用户列表 -->
    <el-card>
        <!-- 点击“添加用户”显示用户信息抽屉框 -->
        <el-button type="primary" @click="showEditUser = true" v-hasButton="'add'">添加用户</el-button>
        <el-button type="danger" plain @click="deleteUserList" v-hasButton="'remove'">批量删除</el-button>
        <!-- 批量删除用户的第二种方法 -->
        <el-table ref="userTable" border :data="userlist">
            <!-- 批量删除用户的第一种方法（释放以下这行，并注释上一行） -->
            <!-- <el-table ref="userTable" border :data="userlist" @selection-change="selectChange" :disable="!deleteIdList.value.length"> -->
            <el-table-column type="selection"></el-table-column>
            <el-table-column label="序号" type="index" width="70px" align="center"></el-table-column>
            <el-table-column label="ID" prop="id" width="90px" align="center"></el-table-column>
            <el-table-column label="用户姓名" prop="username" min-width="120px"></el-table-column>
            <el-table-column label="用户昵称" prop="name" min-width="130px"></el-table-column>
            <el-table-column label="用户角色" prop="roleName" min-width="120px" show-overflow-tooltip></el-table-column>
            <el-table-column label="创建时间" prop="createTime" min-width="165px"></el-table-column>
            <el-table-column label="更新时间" prop="updateTime" min-width="165px"></el-table-column>
            <el-table-column label="操作" fixed="right" min-width="300px" align="center">
                <template #="{ row, $index }">
                    <el-button type="primary" icon="User" size="small" plain @click="editUserRole(row)" v-hasButton="'assgin'">分配角色</el-button>
                    <el-button type="warning" icon="Edit" size="small" plain @click="editUser(row)" v-hasButton="'update'">编辑</el-button>
                    <el-popconfirm :title="`确认删除 ${row.username} ?`" width="200px" @confirm="deleteUserById(row.id)" v-hasButton="'remove'">
                        <template #reference>
                            <el-button type="danger" icon="Delete" size="small" plain>删除</el-button>
                        </template>
                    </el-popconfirm>
                </template>
            </el-table-column>
        </el-table>
        <el-pagination v-model:current-page="pageNo" v-model:page-size="pageSize" :page-sizes="[5, 7, 9, 10]"
            :background="true" layout="prev, pager, next, jumper, ->, sizes, total" :total="total"
            @size-change="getUserList" @current-change="getUserList(pageNo)" />
    </el-card>
    <!-- 编辑用户信息 -->
    <el-drawer v-model="showEditUser" size="330px" @close="closeUserInfo">
        <template #header>
            <h1>{{ userInfo.id ? '修改用户' : '添加用户' }}</h1>
        </template>
        <template #default>
            <el-form ref="userform" :model="userInfo" :rules="rules">
                <el-form-item label="用户姓名" prop="username">
                    <el-input placeholder="请输入用户姓名" v-model.trim="userInfo.username"></el-input>
                </el-form-item>
                <el-form-item label="用户昵称" prop="name">
                    <el-input placeholder="请输入用户昵称" v-model.trim="userInfo.name"></el-input>
                </el-form-item>
                <el-form-item label="用户密码" prop="password">
                    <el-input placeholder="请输入用户密码" v-model.trim="userInfo.password"></el-input>
                </el-form-item>
            </el-form>
        </template>
        <template #footer>
            <div style="flex: auto">
                <el-button type="primary" @click="confirmUser">确定</el-button>
                <el-button @click="showEditUser = false">取消</el-button>
            </div>
        </template>
    </el-drawer>
    <!-- 编辑用户角色 -->
    <el-drawer v-model="showEditUserRole" size="330px" @close="closeUserInfo">
        <template #header>
            <h1>分配用户角色</h1>
        </template>
        <template #default>
            <el-form>
                <el-form-item label="用户姓名">
                    <el-input placeholder="请输入用户昵称" disabled :value="userInfo.username"></el-input>
                </el-form-item>
                <el-form-item label="角色列表">
                    <el-checkbox v-model="checkAll" :indeterminate="isIndeterminate" @change="handleCheckAllChange">
                        全选
                    </el-checkbox>
                    <el-checkbox-group v-model="userRoles" @change="handleCheckedRolesChange">
                        <!-- label值即为选项值，必须为整个role，否则不匹配userRoles的类型 -->
                        <el-checkbox v-for="role in allRoles" key="index" :label="role">
                            {{ role.roleName }}
                        </el-checkbox>
                    </el-checkbox-group>
                </el-form-item>
            </el-form>
        </template>
        <template #footer>
            <div style="flex: auto">
                <el-button type="primary" @click="confirmUserRole">确定</el-button>
                <el-button @click="showEditUserRole = false">取消</el-button>
            </div>
        </template>
    </el-drawer>
</template>

<script setup lang="ts">
import { nextTick, onMounted, ref, watch } from 'vue';
import { reqUserList, reqAddOrUpdateUser, reqGetUserRole, reqSetUserRole, reqDeleteUserById, reqDeleteUserList } from '@/api/acl/user'
import type { UserInfo, ResUserList, ResUserRole, AllRoles, SetUserRole, ReqSetUserRole } from '@/api/acl/user/type'
import { ElMessage, ElNotification } from 'element-plus';
import useUserStore from '@/store/modules/user';
import Searchbox from './subComponent/searchbox.vue';

onMounted(() => {
    getUserList();
})

// 分页器
// 页码
let pageNo = ref<number>(1)
// 每页数量
let pageSize = ref<number>(5)
// 总页数
let total = ref<number>(0)

// 监听分页器变化，页数变化则重新获取
// watch(() => pageNo.value, () => {
//     getUserList()
// })
// 用户列表
let userlist = ref<UserInfo[]>([])
// 获取用户列表
const getUserList = async (pager = 1) => {
    pageNo.value = pager
    let result: ResUserList
    // 若需要搜索
    if (clickSearch.value && searchInput.value)
        // 三个参数：页数、每页行数，搜索的用户名
        result = await reqUserList(pageNo.value, pageSize.value, searchInput.value)
    else result = await reqUserList(pageNo.value, pageSize.value)
    if (result.code == 200) {
        userlist.value = result.data.records;
        total.value = result.data.total;
    }
}

//顶部搜索和重置
// 搜索框内容
let searchInput = ref<string>('')
// 监听当前用户列表是否为搜索结果
let clickSearch = ref<boolean>(false)
// 点击搜索按钮（获取子组件数据）
const searchUser = (value: string) => {
    clickSearch.value = true
    searchInput.value = value
    getUserList()
}
// 点击重置按钮（子组件事件）
const resetUserList = () => {
    clickSearch.value = false
    searchInput.value = ''
    pageSize.value = 5
    getUserList()
}

// 显示添加用户抽屉框
let showEditUser = ref<boolean>(false)
// 要添加用户的信息
let emptyUser = <UserInfo>{
    username: '',
    name: '',
    password: ''
}
let userInfo = ref<UserInfo>({ ...emptyUser })
// 获取当前用户，用于判断是否修改了当前用户
let curEditUser = { ...emptyUser };
// 获取用户小仓库，用于判断当前用户
let userStore = useUserStore();
// 用户表单对象
let userform = ref()

// 点击修改用户按钮
const editUser = (row: UserInfo) => {
    // 先解构再获取，否则响应式会影响table数据
    userInfo.value = { ...row }
    showEditUser.value = true
    // 修改当前用户（将修改前的数据保存）
    // if (row.username == currentUserName)
    curEditUser = { ...userInfo.value }
}

// 用户信息编辑确认按钮（服务器端的添加用户接口有误，响应结果为404）
const confirmUser = async () => {
    // 主动进行表单校验
    await userform.value.validate();
    let result = await reqAddOrUpdateUser(userInfo.value);
    if (result.code == 200) {
        ElMessage.success(userInfo.value.id ? '修改成功' : '添加成功')
        showEditUser.value = false
        // 若为添加新用户，则重新获取第一页，否则获取当前页
        if (!userInfo.value.id) getUserList();
        else getUserList(pageNo.value)
        // 若修改的是当前用户的账号或密码，则重新登录
        if (curEditUser.username == userStore.username && (curEditUser.username !=
            userInfo.value.username || curEditUser.password != userInfo.value.password)) {
            ElNotification.warning('账号或密码已被修改，即将重新登录')
            setTimeout(() => {
                // 刷新页面，自动触发路由守卫，重定向到登录页面
                userStore.username = ''
                window.location.reload();
            }, 3000)
        }
    }
    else ElMessage.error(userInfo.value.id ? '修改失败' : '添加失败')
}

// 表单校验规则
const rules = {
    username: [{ required: true, min: 5, message: '用户名至少5位', trigger: 'blur' }],
    name: [{ required: true, min: 5, message: '用户昵称至少5位', trigger: 'blur' }],
    password: [{ required: true, min: 6, message: '用户密码至少6位', trigger: 'blur' }]
}

// 关闭时，清空用户表单数据和验证信息
const closeUserInfo = () => {
    // 清空表单数据
    userInfo.value = userInfo.value = { ...emptyUser }
    // 清除表单验证信息（nextTick避免第一次DOM加载报错）
    nextTick(() => {
        userform.value.clearValidate();
    })
}

// 显示设置用户角色抽屉框
let showEditUserRole = ref<boolean>(false)
// 全选按钮的控制
let checkAll = ref<boolean>(false)
// 全选按钮的中间状态
let isIndeterminate = ref<boolean>(false)
// 选中的按钮的值
let userRoles = ref<AllRoles>([])
// 所有按钮选项
let allRoles = ref<AllRoles>([])


// 点击“分配角色”按钮
const editUserRole = async (user: UserInfo) => {
    // 清除上次的数据（请求需要时间，避免此时间内的操作）
    allRoles.value = []
    userRoles.value = []

    // 用户名称锁定，无需担心被修改
    userInfo.value = user

    // 获取用户角色
    let result: ResUserRole = await reqGetUserRole(user.id as number);
    if (result.code != 200) return;

    // 保存用户角色数据
    allRoles.value = result.data.allRolesList;
    userRoles.value = result.data.assignRoles;

    // 显示修改用户角色框
    showEditUserRole.value = true

    // 设置多选框的全选按钮和半选的初始状态
    nextTick(() => {
        let count = userRoles.value.length
        // 全选状态
        checkAll.value = count === allRoles.value.length
        // 半选状态
        isIndeterminate.value = count > 0 && count < allRoles.value.length
    })
}

// 点击全选按钮
const handleCheckAllChange = (value: boolean) => {
    // 为true则全选，否则全不选
    userRoles.value = value ? allRoles.value : []
    // 半选按钮取消
    isIndeterminate.value = false
}
// 点击选择某个角色按钮
const handleCheckedRolesChange = (value: boolean[]) => {
    let count = value.length
    // 若所有选项都被选中，则点亮全选框
    checkAll.value = count === allRoles.value.length
    // 部分选项选中，则使全选按钮为不确定状态
    isIndeterminate.value = count > 0 && count < allRoles.value.length
}

// 确定修改用户角色
const confirmUserRole = async () => {
    // 请求参数
    let data: SetUserRole = {
        roleIdList: userRoles.value.map(item => item.id as number),
        userId: userInfo.value.id as number
    }
    let result: ReqSetUserRole = await reqSetUserRole(data);
    if (result.code == 200) {
        ElMessage.success('设置成功')
        // 重新获取用户列表
        getUserList(pageNo.value)
        // 关闭抽屉框
        showEditUserRole.value = false
    }
    else ElMessage.error('设置失败')
}

// 根据id删除一个用户
const deleteUserById = async (id: number) => {
    let result = await reqDeleteUserById(id);
    if (result.code == 200) {
        ElMessage.success('删除成功')
        // 若删除后当前页没有数据（如最后一页），则返回上一页
        if (userlist.value.length - 1) getUserList(pageNo.value - 1)
        // 重新获取当页数据
        else getUserList(pageNo.value)
    }
    else ElMessage.error('删除失败')
}

// 批量删除用户：第一种方法（每次点击多选框都获取）
// 表头已选择的用户行的ID列表（可以将deleteIdList设置为UserInfo[]，在发请求时才map获取Id，节省性能）
// let deleteIdList = ref<number[]>([])
// 点击表头多选框的回调函数（获取选中的用户ID列表）
// const selectChange = (value: UserInfo[]) => {
//     // 每次点击都map，性能消耗大
//     deleteIdList.value = value.map(item => item.id as number)
// }
// 发请求删除用户
// const deleteUserList = async () => {
//     if (deleteIdList.value.length < 1) {
//         ElMessage.warning('未选择删除的数据')
//         return;
//     }
//     let result = await reqDeleteUserList(deleteIdList.value);
//     if (result.code == 200) {
//         ElMessage.success('删除成功')
//         if (userlist.value.length - 1) getUserList(pageNo.value - 1)
//         else getUserList(pageNo.value)
//     }
//     else ElMessage.error('删除失败')
// }

// 用户信息table实例
let userTable = ref()
// 批量删除用户：第二种方法（发请求前获取）
const deleteUserList = async () => {
    let deleteIdList = userTable.value.getSelectionRows().map((item: UserInfo) => item.id as number);
    if (deleteIdList.length < 1) {
        ElMessage.warning('未选择删除的数据')
        return;
    }
    let result = await reqDeleteUserList(deleteIdList);
    if (result.code == 200) {
        ElMessage.success('删除成功')
        // 若删除后当页无数据，获取上一页数据；否则获取当前页
        if (userlist.value.length - deleteIdList.length) getUserList(pageNo.value - 1)
        else getUserList(pageNo.value)
    }
    else ElMessage.error('删除失败')
}
</script>

<style scoped lang="scss">
.el-card {
    margin-bottom: 10px;

    .el-table {
        margin: 15px 0;
    }
}

.top-form {
    display: flex;
    justify-content: space-between;
}
</style>